hey folks I m having trouble with
# spicedb
c
hey folks, I'm having trouble with implementing the lookup resource endpoint via grpc and cursor-based pagination. no matter what I do, the results are randomly ordered. which is expected, as it streams the results I guess. but how do I determine the last cursor to use for the next page? I'm using spicedb-java via kotlin and no matter if I use the while hasNext: next() pattern or forEach/forEachRemaining, my pages end up random. Sadly the apparently auto-generated code is horrible to use 😦 Would appreciate any hints!
My implementation right now:
Copy code
fun getSubjectsForRelation(
        objType: String,
        subject: String,
        subjectId: String,
        permission: String,
        pagination: SpiceDbPagination? = null
    ): PaginatedResult<String> {
        val request = LookupResourcesRequest.newBuilder()
            .setSubject(buildSubjectRef(subject, subjectId))
            .setPermission(permission)
            .setResourceObjectType(objType)
            .apply {
                if (pagination != null) {
                    // the first page has a null cursor
                    if (pagination.cursor != null) {
                        optionalCursor = Cursor.newBuilder().setToken(pagination.cursor).build()
                    }
                    optionalLimit = pagination.limit
                }
            }
            .build()

        val response = permissionsService.lookupResources(request)
        var results = mutableListOf<String>()
        var cursor: Cursor? = null

        while (response.hasNext()) {
            val next = response.next()
            cursor = next.afterResultCursor
            results.add(next.resourceObjectId)
        }

        return PaginatedResult(
            results,
            SpiceDbPagination(cursor?.token, pagination?.limit ?: results.size)
        )
    }
j
The cursor is on each result
Pick the last seen results cursor and send it to the best call
Next*
c
got it! and is it expected behaviour that the second (and last page) returns the same cursor as the current page? I would've expected the cursor to be null
the items returned seem to be correct, but the cursor is confusing me
j
the cursor is simply "this is where to resume"
once you get back less results than requested
you know its the last page
you can, of course, make one more call with the cursor
and it should be empty
but no need to do that if you don't want
it should also be noted that you can (and will) get duplicate resource IDs when using cursoring
but the cursor itself should never repeat
c
ok got it. my unit test is exactly "get 5 out of 10", so two pages are exhausting
oh ok, haven't seen that yet
thank you
j
if you have two "paths" to the same permission
it'll return both
or rather, may
c
gotcha, thank you! much appreciated 🤝
just to clarify: with paths you mean relations that grand the permission?
j
yeah
so imagine this schema
Copy code
definition user {}

definition resource {
  relation viewer: user
  relation editor: user
  permission view = viewer + editor
}
now imagine a user has both
viewer
and
editor
role (for some reason)
and you ask for all resources that the user can
view
the same resource ID might be returned twice
because there are two paths
this is a very simple example
so we likely can deduplicate on our end in that scenario
c
yeah, I understand that! we have a similar setup where a permission is either granted for owners or when a viewer. so if you have both, you have two paths
j
yep!
exactly
c
appreciate the detailed explanation
j
of course
c
I have a weird problem left tho
j
what's that?
c
expected: but was: Expected :[5] Actual :[2] that sometimes happens 🤷‍♂️
I'm getting less results than queried for sometimes, pretty randomly
j
are you on the latest SpiceDB?
there was an issue in v1.22 around this
which was fixed for v1.23
c
let me set the version explicitly, I'm using authzed/spicedb:latest but I think testcontainers should make sure that this is the latest indeed 🤔
j
I'd recommend avoiding using a
latest
tag
just because it moves
and you may have an older version in your local Docker cache
or somesuch
always best to use an explicit tag
10 Views